/*
 * Copyright 2023-2025, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * 龙芯LoongArch64架构缓存管理实现
 * 本文件实现LoongArch64架构的缓存管理功能
 */

#include <KernelExport.h>

#include <arch/cpu.h>
#include <boot/kernel_args.h>
#include <kernel.h>

// 定义调试输出宏
#define TRACE_CACHE
#ifdef TRACE_CACHE
#define TRACE(x...) dprintf("arch_cache: " x)
#else
#define TRACE(x...) ;
#endif

// 龙芯3A6000缓存操作指令
#define CACOP_ICACHE_INDEX_INVALID         0x00    // I-cache按索引无效化
#define CACOP_ICACHE_INDEX_STORE_TAG       0x01    // I-cache按索引存储标记
#define CACOP_ICACHE_HIT_INVALID           0x02    // I-cache按命中无效化
#define CACOP_DCACHE_INDEX_WB_INVALID      0x08    // D-cache按索引回写无效化
#define CACOP_DCACHE_INDEX_STORE_TAG       0x09    // D-cache按索引存储标记
#define CACOP_DCACHE_HIT_INVALID           0x0a    // D-cache按命中无效化
#define CACOP_DCACHE_HIT_WB                0x0b    // D-cache按命中回写
#define CACOP_DCACHE_HIT_WB_INVALID        0x0c    // D-cache按命中回写无效化
#define CACOP_SCACHE_INDEX_WB_INVALID      0x10    // S-cache按索引回写无效化
#define CACOP_SCACHE_INDEX_STORE_TAG       0x11    // S-cache按索引存储标记
#define CACOP_SCACHE_HIT_INVALID           0x12    // S-cache按命中无效化
#define CACOP_SCACHE_HIT_WB                0x13    // S-cache按命中回写
#define CACOP_SCACHE_HIT_WB_INVALID        0x14    // S-cache按命中回写无效化

// 缓存信息结构
struct cache_info {
    uint32 line_size;    // 缓存行大小
    uint32 num_ways;     // 相联度
    uint32 num_sets;     // 组数
    uint32 size;         // 总大小
};

// 全局缓存信息
static cache_info sL1ICache;  // L1指令缓存
static cache_info sL1DCache;  // L1数据缓存
static cache_info sL2Cache;   // L2缓存
static cache_info sL3Cache;   // L3缓存

// 执行缓存操作指令
static inline void
exec_cacop(uint32 op, addr_t addr)
{
    asm volatile("cacop %0, %1, 0" : : "i"(op), "r"(addr) : "memory");
}

// 读取CPUCFG寄存器
static inline uint32
read_cpucfg(uint32 reg)
{
    uint32 val;
    asm volatile(
        "cpucfg %0, %1\n\t"
        : "=r"(val)
        : "r"(reg));
    return val;
}

// 初始化缓存信息
status_t
arch_cache_init(kernel_args *args)
{
    TRACE("Initializing cache\n");

    // 读取缓存信息
    uint32 cpucfg3 = read_cpucfg(3);  // L1I缓存信息
    uint32 cpucfg4 = read_cpucfg(4);  // L1D缓存信息
    uint32 cpucfg5 = read_cpucfg(5);  // L2缓存信息
    uint32 cpucfg6 = read_cpucfg(6);  // L3缓存信息

    // 解析L1I缓存信息
    if (cpucfg3 & 0x1) {
        sL1ICache.line_size = 1 << ((cpucfg3 >> 6) & 0xf);
        sL1ICache.num_ways = 1 << ((cpucfg3 >> 10) & 0xf);
        sL1ICache.num_sets = 1 << ((cpucfg3 >> 14) & 0xf);
        sL1ICache.size = sL1ICache.line_size * sL1ICache.num_ways * sL1ICache.num_sets;
        
        TRACE("L1 I-Cache: %lu KB, %lu-way, %lu byte lines\n", 
              sL1ICache.size / 1024, sL1ICache.num_ways, sL1ICache.line_size);
    }

    // 解析L1D缓存信息
    if (cpucfg4 & 0x1) {
        sL1DCache.line_size = 1 << ((cpucfg4 >> 6) & 0xf);
        sL1DCache.num_ways = 1 << ((cpucfg4 >> 10) & 0xf);
        sL1DCache.num_sets = 1 << ((cpucfg4 >> 14) & 0xf);
        sL1DCache.size = sL1DCache.line_size * sL1DCache.num_ways * sL1DCache.num_sets;
        
        TRACE("L1 D-Cache: %lu KB, %lu-way, %lu byte lines\n", 
              sL1DCache.size / 1024, sL1DCache.num_ways, sL1DCache.line_size);
    }

    // 解析L2缓存信息
    if (cpucfg5 & 0x1) {
        sL2Cache.line_size = 1 << ((cpucfg5 >> 6) & 0xf);
        sL2Cache.num_ways = 1 << ((cpucfg5 >> 10) & 0xf);
        sL2Cache.num_sets = 1 << ((cpucfg5 >> 14) & 0xf);
        sL2Cache.size = sL2Cache.line_size * sL2Cache.num_ways * sL2Cache.num_sets;
        
        TRACE("L2 Cache: %lu KB, %lu-way, %lu byte lines\n", 
              sL2Cache.size / 1024, sL2Cache.num_ways, sL2Cache.line_size);
    }

    // 解析L3缓存信息
    if (cpucfg6 & 0x1) {
        sL3Cache.line_size = 1 << ((cpucfg6 >> 6) & 0xf);
        sL3Cache.num_ways = 1 << ((cpucfg6 >> 10) & 0xf);
        sL3Cache.num_sets = 1 << ((cpucfg6 >> 14) & 0xf);
        sL3Cache.size = sL3Cache.line_size * sL3Cache.num_ways * sL3Cache.num_sets;
        
        TRACE("L3 Cache: %lu KB, %lu-way, %lu byte lines\n", 
              sL3Cache.size / 1024, sL3Cache.num_ways, sL3Cache.line_size);
    }

    return B_OK;
}

// 同步指令缓存
void
arch_cpu_sync_icache(void *address, size_t len)
{
    addr_t start = (addr_t)address;
    addr_t end = start + len;
    addr_t addr;

    // 确保数据缓存回写
    for (addr = start & ~(sL1DCache.line_size - 1); addr < end; addr += sL1DCache.line_size) {
        exec_cacop(CACOP_DCACHE_HIT_WB, addr);
    }

    // 内存屏障，确保数据缓存回写完成
    asm volatile("dbar 0" ::: "memory");

    // 无效化指令缓存
    for (addr = start & ~(sL1ICache.line_size - 1); addr < end; addr += sL1ICache.line_size) {
        exec_cacop(CACOP_ICACHE_HIT_INVALID, addr);
    }

    // 内存屏障，确保指令缓存无效化完成
    asm volatile("dbar 0" ::: "memory");
}

// 无效化TLB范围
void
arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
{
    // 使用INVTLB指令无效化指定范围的TLB
    // INVTLB 4, $r0, $r1 - 无效化指定ASID和VA页的TLB
    uint32 asid;
    asm volatile("csrrd %0, 0x18" : "=r"(asid)); // 读取当前ASID

    addr_t addr;
    for (addr = start & ~(B_PAGE_SIZE - 1); addr < end; addr += B_PAGE_SIZE) {
        asm volatile(
            "invtlb 4, %0, %1"
            : 
            : "r"(asid), "r"(addr)
            : "memory");
    }
}

// 无效化TLB列表
void
arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
{
    // 使用INVTLB指令无效化指定页的TLB
    uint32 asid;
    asm volatile("csrrd %0, 0x18" : "=r"(asid)); // 读取当前ASID

    for (int i = 0; i < num_pages; i++) {
        asm volatile(
            "invtlb 4, %0, %1"
            : 
            : "r"(asid), "r"(pages[i])
            : "memory");
    }
}

// 全局无效化TLB
void
arch_cpu_global_TLB_invalidate(void)
{
    // 使用INVTLB指令无效化所有TLB
    // INVTLB 0, $r0, $r0 - 无效化所有TLB
    asm volatile(
        "invtlb 0, $zero, $zero"
        ::: "memory");
}

// 用户空间无效化TLB
void
arch_cpu_user_TLB_invalidate(void)
{
    // 使用INVTLB指令无效化用户空间TLB
    // INVTLB 1, $r0, $r0 - 无效化指定ASID的TLB
    uint32 asid;
    asm volatile("csrrd %0, 0x18" : "=r"(asid)); // 读取当前ASID

    asm volatile(
        "invtlb 1, %0, $zero"
        : 
        : "r"(asid)
        : "memory");
}